﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Txt2PajekLarge
{
    class BigDictionary<TKey, TValue>
    {
        private Dictionary<int, Dictionary<TKey, TValue>> _dic = new Dictionary<int, Dictionary<TKey, TValue>>();
        private int _nMaxItemPerPart = 40000000;
        private int _nPartCount=0;

        #region property
        public int MaxItemPerPart
        { 
            get { return _nMaxItemPerPart; }
            set { _nMaxItemPerPart = value; }
        }

        public long Count
        {
            get
            {
                long result = 0;
                for (int i = 0; i < _nPartCount; i++)
                    result += _dic[i].Count;
                return result;
            }
        }

        public TValue this[TKey Key]
        {
            get 
            {
                try
                {
                    for (int i = 0; i < _nPartCount; i++)
                        if (_dic[i].ContainsKey(Key))
                            return _dic[i][Key];

                    KeyNotFoundException e = new KeyNotFoundException();
                    throw e;
                }
                catch { throw; }
            }
            set
            {
                try
                {
                    bool found = false;
                    for (int i = 0; i < _nPartCount; i++)
                        if (_dic[i].ContainsKey(Key))
                        {
                            _dic[i][Key] = value;
                            found = true;
                            break;
                        }
                    if (!found)
                    {
                        KeyNotFoundException e = new KeyNotFoundException();
                        throw e;
                    }
                }
                catch { throw; }
            }
        }
        #endregion

        public void Add(TKey Key, TValue Value)
        {
            try
            {
                bool added = false;
                for (int i = 0; i < _nPartCount; i++)
                {
                    if (_dic[i].ContainsKey(Key))
                    {
                        ArgumentException e = new ArgumentException("Key " + Key.ToString() + " has exists.");
                        throw e;
                    }
                    if (_dic[i].Count < _nMaxItemPerPart)
                    {
                        _dic[i].Add(Key, Value);
                        added = true;
                        break;
                    }
                }
                if (!added)
                {
                    _dic.Add(_dic.Count, new Dictionary<TKey, TValue>());
                    _nPartCount++;
                    _dic[_nPartCount - 1].Add(Key, Value);
                    added = true;
                }
            }
            catch { throw; }
        }

        public bool Remove(TKey Key)
        {
            try
            {
                for (int i = 0; i < _nPartCount; i++)
                    if (_dic[i].Remove(Key))
                    {
                        if (_dic[i].Count == 0)
                        {
                            _dic.Remove(i);
                            _nPartCount--;
                        }
                        return true;
                    }
                return false;
            }
            catch { throw; }
        }

        public void Clear()
        {
            for (int i = 0; i < _nPartCount; i++) _dic[i].Clear();
            _dic.Clear();
            _nPartCount = 0;
        }

        public bool ContainsKey(TKey Key)
        {
            try
            {
                for (int i = 0; i < _nPartCount; i++)
                    if (_dic[i].ContainsKey(Key)) return true;
                return false;
            }
            catch { throw; }
        }

        public bool ContainsValue(TValue Value)
        {
            try
            {
                for (int i = 0; i < _nPartCount; i++)
                    if(_dic[i].ContainsValue(Value))    return true;
                return false;
            }
            catch { throw; }
        }
    }
}
